package com.conversationboard.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.concurrent.CopyOnWriteArrayList;

import com.conversationboard.model.exceptions.MessageNotFoundException;

/** Changed the approach for this again. The "messages" object used to be a LinkedList<Message>, but an
 * ArrayList is fine, since it's always appended to the bottom. I have used the
 * java.util.concurrent.CopyOnWriteArrayList, which is designed to ensure that any updates to the list are
 * done to a copy, rather than the main list, and then this is atomically swapped in, in order that we remove
 * any threading issues, or ConcurrentUpdateExceptions.
 * 
 * @author Keith Watson */

public final class Messages implements List<Message> {

	private static final long FIVE_DAYS_IN_MILLISECONDS = 432000000;
	private List<Message> messages = new CopyOnWriteArrayList<Message>();
	private static final int RETURN_RECENT_MESSAGES = 5;


	public Message getLastMessage() {
		return this.messages.get(messages.size() - 1);
	}


	/** For Blog View - returns the most recent few messages on this thread.
	 * 
	 * @return */

	public List<Message> getRecentMessages() {

		int numberOfMessages = messages.size();

		/* Return them all, if there are fewer than the number of messages we return in the message list */

		if (numberOfMessages <= RETURN_RECENT_MESSAGES) {
			for (Message message : this.messages) {
				List<Message> recentMessages = new ArrayList<Message>(numberOfMessages);
				recentMessages.add(message);

				return messages;
			}
		}

		List<Message> recentMessages = new ArrayList<Message>(RETURN_RECENT_MESSAGES);

		int startAt = numberOfMessages - RETURN_RECENT_MESSAGES - 1;

		for (int i = startAt; i < numberOfMessages; i++) {
			recentMessages.add(this.messages.get(i));
		}

		return recentMessages;
	}


	public int getNumberOfRecentMessages() {

		long now = new Date().getTime();
		int recentMessages = 0;
		boolean first = true;

		for (Message message : this) {

			/* Don't count the question's message in the new answers count */

			if (first) {
				first = false;
				continue;
			}

			long messageTime = message.getTimestamp().getTime();
			long difference = (now - messageTime);

			if (difference < FIVE_DAYS_IN_MILLISECONDS) {
				recentMessages++;
			}
		}

		return recentMessages;
	}


	public int getIndexFromMessageId(int messageId) throws MessageNotFoundException {

		/* Start from the last message and go back one by one until we find the messages */

		int size = this.messages.size() - 1;

		for (int i = size; i >= 0; i--) {

			if (this.messages.get(i).getMessageId() == messageId) {
				return i;
			}
		}

		throw new MessageNotFoundException();
	}


	public void add(int arg0, Message arg1) {
		messages.add(arg0, arg1);
	}


	public boolean add(Message arg0) {
		return messages.add(arg0);
	}


	public boolean addAll(Collection<? extends Message> arg0) {
		return messages.addAll(arg0);
	}


	public boolean addAll(int arg0, Collection<? extends Message> arg1) {
		return messages.addAll(arg0, arg1);
	}


	public void clear() {
		messages.clear();
	}


	public boolean contains(Object arg0) {
		return messages.contains(arg0);
	}


	public boolean containsAll(Collection<?> arg0) {
		return messages.containsAll(arg0);
	}


	public boolean equals(Object arg0) {
		return messages.equals(arg0);
	}


	public Message get(int arg0) {
		return messages.get(arg0);
	}


	public int hashCode() {
		return messages.hashCode();
	}


	public int indexOf(Object arg0) {
		return messages.indexOf(arg0);
	}


	public boolean isEmpty() {
		return messages.isEmpty();
	}


	public Iterator<Message> iterator() {
		return messages.iterator();
	}


	public int lastIndexOf(Object arg0) {
		return messages.lastIndexOf(arg0);
	}


	public ListIterator<Message> listIterator() {
		return messages.listIterator();
	}


	public ListIterator<Message> listIterator(int arg0) {
		return messages.listIterator(arg0);
	}


	public Message remove(int arg0) {
		return messages.remove(arg0);
	}


	public boolean remove(Object arg0) {
		return messages.remove(arg0);
	}


	public boolean removeAll(Collection<?> arg0) {
		return messages.removeAll(arg0);
	}


	public boolean retainAll(Collection<?> arg0) {
		return messages.retainAll(arg0);
	}


	public Message set(int arg0, Message arg1) {
		return messages.set(arg0, arg1);
	}


	public int size() {
		return messages.size();
	}


	public List<Message> subList(int arg0, int arg1) {
		return messages.subList(arg0, arg1);
	}


	public Object[] toArray() {
		return messages.toArray();
	}


	public <T> T[] toArray(T[] arg0) {
		return messages.toArray(arg0);
	}

}
